-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add history undo
command
#1452
Add history undo
command
#1452
Conversation
May I ask you why users wants to use What do you think could be improved in comparison to DNF4? |
This almost looks like a trick-question to me 😅 For me personally the most common use is to uninstall a thing after trying it out, ie typically "undo last". Undoing an upgrade to test whether upgrade broke/fixed stuff would be super useful, but of course that depends on more than just dnf features (the repos dont typically carry all possible versions) |
May be I would be good to be verbose here. In DNF4, history commands are important but not useful much because the implementation is very strict. Undo is very important and can be very powerful. Use case - revert the last transaction, but why
Both operation of the same transaction have a different starting point - some packages might be not on the system. The command does not provide only undo of the last transaction but there is no logic that react to any changes.
This may end up with following results
Another use case
This may end up with following results
Another example:
This may end up with following results
Additional cases with installonly packages. Please don't take it as this implementation is wrong. I would like to brainstorm expectation for various use cases. Also I am sure that I've not covered all possibilities. |
I have also used it for this in the past but now that I think about it
These are basically the same problems that the The
We already have |
I don't think that the option mentioned above answer the question related to expected behavior. They only make no changes if something is unexpected. Lets return to the first example
The current behavior reports nothing to do with success and any of those options would help. I don't think that success is a correct result of the transaction, because it did nothing. For this situation a user might expect
|
Yes I meant that in addition to those options we would make the command more strict (like the dnf4 Regarding the possibilities you listed:
This sounds like a rollback, personally I don't like this behavior for
As far as I understand this is the current behavior.
This would be the new default behavior and the user could specify What do you think? |
I think this is a better option then the current behavior. It requires good messaging to ensure that user understand the problem and possible solutions. |
e3df7c9
to
998aedd
Compare
Ok I have added several commits and I tried to focus on clear messages and logs. @j-mracek for the cases you mentioned it looks something like this:
(With
(Same as the previous example.)
(This is a change in comparison to dnf4, the |
} else if ( | ||
package_replay.action == Action::REMOVE && | ||
(pkg.get_reason() == Reason::DEPENDENCY || pkg.get_reason() == Reason::WEAK_DEPENDENCY)) { | ||
package_replay.reason = Reason::CLEAN; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you why the reason is set here to CLEAN
? What about to not set no reason for any remove step?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking was that this makes the transaction table more consistent.
It basically ensures that the removed dependencies are reported as Removing unused dependencies
(like they would be for normal [not-reverted] transaction) not as Removing dependent packages
.
If we keep the DEPENDENCY
or WEAK_DEPENDENCY
this reason is saved to the history because after resolving the replay code overrides the reasons.
However if there is some problem with this I am not against dropping it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, this is a good idea. I am just curious whether the reason might be something else then user
. Please keep it like it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason can be group and the remove operation works nicely.
cd6b4d8
to
cf9c5c5
Compare
I have tested several scenario and it looks good. Only one thing is not perfect and it is related to messaging when a different version is installed and undo is supposed to remove. The behavior is correct.
In this case I would prefer to inform that 'a-1-1.noarch' is installed in a different version. And which one. The reason is that |
libdnf5/base/goal.cpp
Outdated
} | ||
group_replay.action = reverted_action->second; | ||
} else { | ||
group_replay.action = transaction::TransactionItemAction::UPGRADE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tested it and I think that the revert of upgrade by upgrade is confusing. I am suggesting to add a warning, that group upgrade operation cannot be reverted, only RPMs will be modify. No error, only a warning. Or not a warning but event log would be better (new type I guess).
libdnf5/base/goal.cpp
Outdated
} | ||
env_replay.action = reverted_action->second; | ||
} else { | ||
env_replay.action = transaction::TransactionItemAction::UPGRADE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am recommending to not present the operation as an upgrade, because in background it does nothing. But if new group appeared then it might modify groups.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I have turned into it a log event. Now a revert of a revert of group upgrade won't mention the group at all because the group action will disappear on the first revert but I think that is acceptable.
libdnf5/base/goal.cpp
Outdated
|
||
// Don't fill in @System repo_id because it's not possible to perform forward actions from it | ||
if (env.get_repoid() != "@System") { | ||
env_replay.repo_id = env.get_repoid(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that this is the same type of problem like with RPMs. What about to not use repo_id for undo?
libdnf5/base/goal.cpp
Outdated
} | ||
|
||
// Don't fill in @System repo_id because it's not possible to perform forward actions from it | ||
if (group.get_repoid() != "@System") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that this is the same type of problem like with RPMs. What about to not use repo_id for undo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am even not sure whether for groups it make sense to handle repo_id at all because they are merged from multiple sources.
libdnf5/base/goal.cpp
Outdated
|
||
const auto nevras = rpm::Nevra::parse(package_replay.nevra, {rpm::Nevra::Form::NEVRA}); | ||
libdnf_assert( | ||
nevras.size() > 0, "Cannot parse rpm nevra \"{}\" while replaying transaction.", package_replay.nevra); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about to change a condition - nevras.size() == 1
. I believe that NEVRA type has only one solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
libdnf5/base/log_event.cpp
Outdated
@@ -153,23 +153,52 @@ std::string LogEvent::to_string( | |||
} else { | |||
return ret.append(utils::sformat(_("No match for group package: {}"), *spec)); | |||
} | |||
} else if (goal_action_is_replay(action)) { | |||
return ret.append( | |||
utils::sformat(_("Cannot perform {}, no match for: {}."), goal_action_to_string(action), *spec)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you to mark an order of arguments {1}
. It will allow to change order for translators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
libdnf5/base/log_event.cpp
Outdated
case GoalProblem::NOT_INSTALLED: { | ||
if (goal_action_is_replay(action)) { | ||
return ret.append(utils::sformat( | ||
_("Cannot perform {} for {} '{}' becasue it is not installed."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you to mark an order of arguments {1}
. It will allow to change order for translators. In this case what about to provide a context message for translators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the marks but I don't know what are context messages? Can we perhaps add them separately?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used to explain what message means. The method is C_(<message for translaters>, <string to translate>)
with two string arguments and in DNF5 it is used only here -
dnf5/libdnf5/base/transaction.cpp
Line 1373 in 3fa8d63
repos_with_skipped_checks, C_("It is a joining character for repositories IDs", ", ")); |
libdnf5/base/log_event.cpp
Outdated
case GoalProblem::NOT_INSTALLED_FOR_ARCHITECTURE: | ||
return ret.append(utils::sformat( | ||
_("Packages for argument '{}' available, but installed for a different architecture."), *spec)); | ||
case GoalProblem::ONLY_SRC: | ||
if (goal_action_is_replay(action)) { | ||
return ret.append(utils::sformat( | ||
_("Cannot perform {} because '{}' matches only source packages."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you to mark an order of arguments {1}
. It will allow to change order for translators. In this case what about to provide a context message for translators? In this case the context message is questionable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the marks but I don't know what are context messages? Can we perhaps add them separately?
libdnf5/base/log_event.cpp
Outdated
return ret.append(utils::sformat(_("Argument '{}' matches only source packages."), *spec)); | ||
case GoalProblem::EXCLUDED: | ||
if (goal_action_is_replay(action)) { | ||
return ret.append(utils::sformat( | ||
_("Cannot perform {} because '{}' matches only excluded packages."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you to mark an order of arguments {1}
. It will allow to change order for translators. In this case what about to provide a context message for translators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the marks but I don't know what are context messages? Can we perhaps add them separately?
libdnf5/base/log_event.cpp
Outdated
return ret.append(utils::sformat(_("Argument '{}' matches only excluded packages."), *spec)); | ||
case GoalProblem::EXCLUDED_VERSIONLOCK: | ||
if (goal_action_is_replay(action)) { | ||
return ret.append(utils::sformat( | ||
_("Cannot perform {} because '{}' matches only packages excluded by versionlock."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you to mark an order of arguments {1}
. It will allow to change order for translators. In this case what about to provide a context message for translators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the marks but I don't know what are context messages? Can we perhaps add them separately?
libdnf5/base/log_event.cpp
Outdated
_("Packages for argument '{}' installed and available, but in a different version => cannot " | ||
"reinstall"), | ||
*spec)); | ||
_("Installed packages for argument '{}' are not available in repositories in the same version, " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you to mark an order of arguments {1}
. It will allow to change order for translators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
libdnf5/base/log_event.cpp
Outdated
libdnf5::utils::string::join(additional_data, ","))); | ||
} else if (goal_action_is_replay(action)) { | ||
return ret.append(utils::sformat( | ||
_("Cannot perform {} because '{}' is installed in a different version: '{}'."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you to mark an order of arguments {1}
. It will allow to change order for translators. In this case what about to provide a context message for translators? Subjects are not explicitly mentioned, therefore the message without a context might be not clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the marks but I don't know what are context messages? Can we perhaps add them separately?
libdnf5/base/log_event.cpp
Outdated
@@ -220,6 +256,13 @@ std::string LogEvent::to_string( | |||
case GoalProblem::WRITE_DEBUG: | |||
return ret.append(utils::sformat(_("Debug data written to \"{}\""), *additional_data.begin())); | |||
case GoalProblem::UNSUPPORTED_ACTION: | |||
if (action == GoalAction::REVERT_COMPS_UPGRADE) { | |||
return ret.append(utils::sformat( | |||
_("{} upgrade cannot be reverted, however associated package actions will be. ({} id: '{}') ."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you to mark an order of arguments {1}
. It will allow to change order for translators. In this case what about to provide a context message for translators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the marks but I don't know what are context messages? Can we perhaps add them separately?
libdnf5/base/log_event.cpp
Outdated
@@ -287,6 +330,13 @@ std::string LogEvent::to_string( | |||
_("Error: It is not possible to switch enabled streams of a module unless explicitly enabled via " | |||
"configuration option module_stream_switch.")); | |||
} | |||
case GoalProblem::EXTRA: { | |||
return ret.append(utils::sformat( | |||
_("Extra package '{}' (with action '{}') which is not present in the stored transaction was pulled " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you to mark an order of arguments {1}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
@@ -49,6 +49,7 @@ struct PackageReplay { | |||
TransactionItemAction action; | |||
TransactionItemReason reason; | |||
std::string group_id; | |||
// This nevra doesn't contain epoch if it is 0 | |||
std::string nevra; | |||
std::filesystem::path package_path; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask you for a doc string for a package path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for the PR update. This version is is good, but I have some suggestions that are not critical, let say they are more cosmetic. It means, it works according to expectations.
It adds checks for expected packages in transaction replay producing either a warning or an error if something is missing. This matches the dnf4 implementation.
It is configured by `ignore_extras` and `ignore_installed` `GoalJobSettings`. This matches the functionality in dnf4. It also removes some unused imports in transaction.cpp
LGTM, documentation will be delivered in the next PR. |
af8f535
PR that adds the API (rpm-software-management#1452) was merged right before rpm-software-management#1307 so its missing there.
It adds
add_revert_transaction(...)
API toGoal
. This is used byundo
and later should also be used forrollback
but that requires merging of history transactions.For #140.